package com.stylefeng.guns.poi.pl;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.ListUtils;
import org.springframework.util.StringUtils;

import com.alibaba.fastjson.util.IOUtils;

public class FileUtils {
	public final static String FILE_EXTENSION_SEPARATOR = ".";

	private FileUtils() {
		throw new AssertionError();
	}

	/**
	 * read file
	 * 
	 * @param filePath
	 * @param charsetName The name of a supported {@link java.nio.charset.Charset </code>charset<code>}
	 * @return if file not exist, return null, else return content of file
	 * @throws RuntimeException if an error occurs while operator BufferedReader
	 */
	public static StringBuilder readFile(String filePath, String charsetName) {
		File file = new File(filePath);
		StringBuilder fileContent = new StringBuilder("");
		if (file == null || !file.isFile()) {
			return null;
		}

		BufferedReader reader = null;
		try {
			InputStreamReader is = new InputStreamReader(new FileInputStream(file), charsetName);
			reader = new BufferedReader(is);
			String line = null;
			while ((line = reader.readLine()) != null) {
				if (!fileContent.toString().equals("")) {
					fileContent.append("\r\n");
				}
				fileContent.append(line);
			}
			return fileContent;
		} catch (IOException e) {
			throw new RuntimeException("IOException occurred. ", e);
		} finally {
			IOUtils.close(reader);
		}
	}

	/**
	 * write file
	 * 
	 * @param filePath
	 * @param content
	 * @param append is append, if true, write to the end of file, else clear content of file and write into it
	 * @return return false if content is empty, true otherwise
	 * @throws RuntimeException if an error occurs while operator FileWriter
	 */
	public static boolean writeFile(String filePath, String content, boolean append) {
		if (StringUtils.isEmpty(content)) {
			return false;
		}

		FileWriter fileWriter = null;
		try {
			makeDirs(filePath);
			fileWriter = new FileWriter(filePath, append);
			fileWriter.write(content);
			return true;
		} catch (IOException e) {
			throw new RuntimeException("IOException occurred. ", e);
		} finally {
			IOUtils.close(fileWriter);
		}
	}

	/**
	 * write file
	 * 
	 * @param filePath
	 * @param contentList
	 * @param append is append, if true, write to the end of file, else clear content of file and write into it
	 * @return return false if contentList is empty, true otherwise
	 * @throws RuntimeException if an error occurs while operator FileWriter
	 */
	public static boolean writeFile(String filePath, List<String> contentList, boolean append) {
		FileWriter fileWriter = null;		try {			makeDirs(filePath);			fileWriter = new FileWriter(filePath, append);			int i = 0;			for (String line : contentList) {				if (i++ > 0) {					fileWriter.write("\r\n");				}				fileWriter.write(line);			}			return true;		} catch (IOException e) {			throw new RuntimeException("IOException occurred. ", e);		} finally {			IOUtils.close(fileWriter);		}
	}

	/**	 * write file, the string will be written to the begin of the file	 * 	 * @param filePath	 * @param content	 * @return	 */
	public static boolean writeFile(String filePath, String content) {		return writeFile(filePath, content, false);
	}

	/**	 * write file, the string list will be written to the begin of the file	 * 	 * @param filePath	 * @param contentList	 * @return	 */
	public static boolean writeFile(String filePath, List<String> contentList) {		return writeFile(filePath, contentList, false);
	}

	/**	 * write file, the bytes will be written to the begin of the file	 * 	 * @param filePath	 * @param stream	 * @return	 * @see {@link #writeFile(String, InputStream, boolean)}	 */
	public static boolean writeFile(String filePath, InputStream stream) {		return writeFile(filePath, stream, false);
	}

	/**	 * write file	 * 	 * @param file the file to be opened for writing.	 * @param stream the input stream	 * @param append if <code>true</code>, then bytes will be written to the end of the file rather than the beginning	 * @return return true	 * @throws RuntimeException if an error occurs while operator FileOutputStream	 */
	public static boolean writeFile(String filePath, InputStream stream, boolean append) {		return writeFile(filePath != null ? new File(filePath) : null, stream, append);
	}

	/**	 * write file, the bytes will be written to the begin of the file	 * 	 * @param file	 * @param stream	 * @return	 * @see {@link #writeFile(File, InputStream, boolean)}	 */
	public static boolean writeFile(File file, InputStream stream) {		return writeFile(file, stream, false);
	}

	/**	 * write file	 * 	 * @param file the file to be opened for writing.	 * @param stream the input stream	 * @param append if <code>true</code>, then bytes will be written to the end of the file rather than the beginning	 * @return return true	 * @throws RuntimeException if an error occurs while operator FileOutputStream	 */
	public static boolean writeFile(File file, InputStream stream, boolean append) {		OutputStream o = null;		try {			makeDirs(file.getAbsolutePath());			o = new FileOutputStream(file, append);			byte data[] = new byte[1024];			int length = -1;			while ((length = stream.read(data)) != -1) {				o.write(data, 0, length);			}			o.flush();			return true;		} catch (FileNotFoundException e) {			throw new RuntimeException("FileNotFoundException occurred. ", e);		} catch (IOException e) {			throw new RuntimeException("IOException occurred. ", e);		} finally {			IOUtils.close(o);			IOUtils.close(stream);		}
	}

	/**	 * move file	 * 	 * @param sourceFilePath	 * @param destFilePath	 */
	public static void moveFile(String sourceFilePath, String destFilePath) {		if(StringUtils.isEmpty(sourceFilePath) ||StringUtils.isEmpty(destFilePath)) {			throw new RuntimeException("Both sourceFilePath and destFilePath cannot be null.");		}		moveFile(new File(sourceFilePath), new File(destFilePath));
	}

	/**	 * move file	 * 	 * @param srcFile	 * @param destFile	 */
	public static void moveFile(File srcFile, File destFile) {		boolean rename = srcFile.renameTo(destFile);		if (!rename) {			copyFile(srcFile.getAbsolutePath(), destFile.getAbsolutePath());			deleteFile(srcFile.getAbsolutePath());		}
	}

	/**	 * copy file	 * 	 * @param sourceFilePath	 * @param destFilePath	 * @return	 * @throws RuntimeException if an error occurs while operator FileOutputStream	 */
	public static boolean copyFile(String sourceFilePath, String destFilePath) {		InputStream inputStream = null;		try {			inputStream = new FileInputStream(sourceFilePath);		} catch (FileNotFoundException e) {			throw new RuntimeException("FileNotFoundException occurred. ", e);		}		return writeFile(destFilePath, inputStream);
	}

	/**	 * read file to string list, a element of list is a line	 * 	 * @param filePath	 * @param charsetName The name of a supported {@link java.nio.charset.Charset </code>charset<code>}	 * @return if file not exist, return null, else return content of file	 * @throws RuntimeException if an error occurs while operator BufferedReader	 */
	public static List<String> readFileToList(String filePath, String charsetName) {		File file = new File(filePath);		List<String> fileContent = new ArrayList<String>();		if (file == null || !file.isFile()) {			return null;		}
		BufferedReader reader = null;		try {			InputStreamReader is = new InputStreamReader(new FileInputStream(file), charsetName);			reader = new BufferedReader(is);			String line = null;			while ((line = reader.readLine()) != null) {				fileContent.add(line);			}			return fileContent;		} catch (IOException e) {			throw new RuntimeException("IOException occurred. ", e);		} finally {			IOUtils.close(reader);		}
	}

	/**	 * get file name from path, not include suffix	 * 	 * <pre>	 *      getFileNameWithoutExtension(null)               =   null	 *      getFileNameWithoutExtension("")                 =   ""	 *      getFileNameWithoutExtension("   ")              =   "   "	 *      getFileNameWithoutExtension("abc")              =   "abc"	 *      getFileNameWithoutExtension("a.mp3")            =   "a"	 *      getFileNameWithoutExtension("a.b.rmvb")         =   "a.b"	 *      getFileNameWithoutExtension("c:\\")              =   ""	 *      getFileNameWithoutExtension("c:\\a")             =   "a"	 *      getFileNameWithoutExtension("c:\\a.b")           =   "a"	 *      getFileNameWithoutExtension("c:a.txt\\a")        =   "a"	 *      getFileNameWithoutExtension("/home/admin")      =   "admin"	 *      getFileNameWithoutExtension("/home/admin/a.txt/b.mp3")  =   "b"	 * </pre>	 * 	 * @param filePath	 * @return file name from path, not include suffix	 * @see	 */
	public static String getFileNameWithoutExtension(String filePath) {		if (StringUtils.isEmpty(filePath)) {			return filePath;		}
		int extenPosi = filePath.lastIndexOf(FILE_EXTENSION_SEPARATOR);		int filePosi = filePath.lastIndexOf(File.separator);		if (filePosi == -1) {			return (extenPosi == -1 ? filePath : filePath.substring(0, extenPosi));		}		if (extenPosi == -1) {			return filePath.substring(filePosi + 1);		}		return (filePosi < extenPosi ? filePath.substring(filePosi + 1, extenPosi) : filePath.substring(filePosi + 1));
	}

	/**	 * get file name from path, include suffix	 * 	 * <pre>	 *      getFileName(null)               =   null	 *      getFileName("")                 =   ""	 *      getFileName("   ")              =   "   "	 *      getFileName("a.mp3")            =   "a.mp3"	 *      getFileName("a.b.rmvb")         =   "a.b.rmvb"	 *      getFileName("abc")              =   "abc"	 *      getFileName("c:\\")              =   ""	 *      getFileName("c:\\a")             =   "a"	 *      getFileName("c:\\a.b")           =   "a.b"	 *      getFileName("c:a.txt\\a")        =   "a"	 *      getFileName("/home/admin")      =   "admin"	 *      getFileName("/home/admin/a.txt/b.mp3")  =   "b.mp3"	 * </pre>	 * 	 * @param filePath	 * @return file name from path, include suffix	 */
	public static String getFileName(String filePath) {		if (StringUtils.isEmpty(filePath)) {			return filePath;		}
		int filePosi = filePath.lastIndexOf(File.separator);		return (filePosi == -1) ? filePath : filePath.substring(filePosi + 1);
	}

	/**	 * get folder name from path	 * 	 * <pre>	 *      getFolderName(null)               =   null	 *      getFolderName("")                 =   ""	 *      getFolderName("   ")              =   ""	 *      getFolderName("a.mp3")            =   ""	 *      getFolderName("a.b.rmvb")         =   ""	 *      getFolderName("abc")              =   ""	 *      getFolderName("c:\\")              =   "c:"	 *      getFolderName("c:\\a")             =   "c:"	 *      getFolderName("c:\\a.b")           =   "c:"	 *      getFolderName("c:a.txt\\a")        =   "c:a.txt"	 *      getFolderName("c:a\\b\\c\\d.txt")    =   "c:a\\b\\c"	 *      getFolderName("/home/admin")      =   "/home"	 *      getFolderName("/home/admin/a.txt/b.mp3")  =   "/home/admin/a.txt"	 * </pre>	 * 	 * @param filePath	 * @return	 */
	public static String getFolderName(String filePath) {
		if (StringUtils.isEmpty(filePath)) {			return filePath;		}
		int filePosi = filePath.lastIndexOf(File.separator);		return (filePosi == -1) ? "" : filePath.substring(0, filePosi);
	}

	/**	 * get suffix of file from path	 * 	 * <pre>	 *      getFileExtension(null)               =   ""	 *      getFileExtension("")                 =   ""	 *      getFileExtension("   ")              =   "   "	 *      getFileExtension("a.mp3")            =   "mp3"	 *      getFileExtension("a.b.rmvb")         =   "rmvb"	 *      getFileExtension("abc")              =   ""	 *      getFileExtension("c:\\")              =   ""	 *      getFileExtension("c:\\a")             =   ""	 *      getFileExtension("c:\\a.b")           =   "b"	 *      getFileExtension("c:a.txt\\a")        =   ""	 *      getFileExtension("/home/admin")      =   ""	 *      getFileExtension("/home/admin/a.txt/b")  =   ""	 *      getFileExtension("/home/admin/a.txt/b.mp3")  =   "mp3"	 * </pre>	 * 	 * @param filePath	 * @return	 */
	public static String getFileExtension(String filePath) {		if (StringUtils.isEmpty(filePath)) {			return filePath;		}
		int extenPosi = filePath.lastIndexOf(FILE_EXTENSION_SEPARATOR);		int filePosi = filePath.lastIndexOf(File.separator);		if (extenPosi == -1) {			return "";		}		return (filePosi >= extenPosi) ? "" : filePath.substring(extenPosi + 1);
	}

	/**	 * Creates the directory named by the trailing filename of this file, including the complete directory path required	 * to create this directory. <br/>	 * <br/>	 * <ul>	 * <strong>Attentions:</strong>	 * <li>makeDirs("C:\\Users\\Trinea") can only create users folder</li>	 * <li>makeFolder("C:\\Users\\Trinea\\") can create Trinea folder</li>	 * </ul>	 * 	 * @param filePath	 * @return true if the necessary directories have been created or the target directory already exists, false one of	 *         the directories can not be created.	 *         <ul>	 *         <li>if {@link FileUtils#getFolderName(String)} return null, return false</li>	 *         <li>if target directory already exists, return true</li>	 *         <li>return {@link File#makeFolder}</li>	 *         </ul>	 */
	public static boolean makeDirs(String filePath) {		String folderName = getFolderName(filePath);		if (StringUtils.isEmpty(folderName)) {			return false;		}
		File folder = new File(folderName);		return (folder.exists() && folder.isDirectory()) ? true : folder.mkdirs();
	}

	/**	 * @param filePath	 * @return	 * @see #makeDirs(String)	 */
	public static boolean makeFolders(String filePath) {		return makeDirs(filePath);
	}

	/**	 * Indicates if this file represents a file on the underlying file system.	 * 	 * @param filePath	 * @return	 */
	public static boolean isFileExist(String filePath) {		if (StringUtils.isEmpty(filePath)) {			return false;		}
		File file = new File(filePath);		return (file.exists() && file.isFile());
	}

	/**	 * Indicates if this file represents a directory on the underlying file system.	 * 	 * @param directoryPath	 * @return	 */
	public static boolean isFolderExist(String directoryPath) {		if (StringUtils.isEmpty(directoryPath)) {			return false;		}
		File dire = new File(directoryPath);		return (dire.exists() && dire.isDirectory());
	}

	/**	 * delete file or directory	 * <ul>	 * <li>if path is null or empty, return true</li>	 * <li>if path not exist, return true</li>	 * <li>if path exist, delete recursion. return true</li>	 * <ul>	 * 	 * @param path	 * @return	 */
	public static boolean deleteFile(String path) {		if (StringUtils.isEmpty(path)) {			return true;		}
		File file = new File(path);		if (!file.exists()) {			return true;		}		if (file.isFile()) {			return file.delete();		}		if (!file.isDirectory()) {			return false;		}		for (File f : file.listFiles()) {			if (f.isFile()) {				f.delete();			} else if (f.isDirectory()) {				deleteFile(f.getAbsolutePath());			}		}		return file.delete();
	}

	/**	 * get file size	 * <ul>	 * <li>if path is null or empty, return -1</li>	 * <li>if path exist and it is a file, return file size, else return -1</li>	 * <ul>	 * 	 * @param path	 * @return returns the length of this file in bytes. returns -1 if the file does not exist.	 */
	public static long getFileSize(String path) {		if (StringUtils.isEmpty(path)) {			return -1;		}
		File file = new File(path);		return (file.exists() && file.isFile() ? file.length() : -1);
	}
	// 判断文件是否存在
	public static boolean judeFileExists(File file) {
		if (file.exists()) {
			return true;
		} 
		return false;
	}

	public static boolean judeFileExists(String path){
		File file = new File(path);
		return judeFileExists(file);
	}	/**	 * 获取目录下的文件名数组	 * @param path	 * @return	 */	public static ArrayList<String> getFiles(String path) {		ArrayList<String> files = new ArrayList<String>();		File file = new File(path);		File[] tempList = file.listFiles();
		for (int i = 0; i < tempList.length; i++) {			if (tempList[i].isFile()) {				files.add(tempList[i].getName());			}			if (tempList[i].isDirectory()) {
			}		}		return files;
	}
	/**	 * 获取目录下的文件名数组	 * @param path	 * @return	 */
	public static ArrayList<Map> getFilesMap(String path) {		ArrayList<Map> files = new ArrayList<Map>();		File file = new File(path);		File[] tempList = file.listFiles();
		for (int i = 0; i < tempList.length; i++) {			Map map = new HashMap();			if (tempList[i].isFile()) {				map.put("name", tempList[i].getName());				files.add(map);			}			if (tempList[i].isDirectory()) {
			}		}		return files;
	}

	public static void writeStringToFile(File file, String content, String string) {
		if (StringUtils.isEmpty(content)) {
			return;
		}

		FileWriter fileWriter = null;
		try {
			fileWriter = new FileWriter(file);
			fileWriter.write(content);
		} catch (IOException e) {
			throw new RuntimeException("IOException occurred. ", e);
		} finally {
			IOUtils.close(fileWriter);
		}
	}
}